package com.sise.parkinglot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sise.parkinglot.bean.CodeMsg;
import com.sise.parkinglot.composition.PublicService;
import com.sise.parkinglot.entity.*;
import com.sise.parkinglot.mapper.*;
import com.sise.parkinglot.service.ISitInfoService;
import com.sise.parkinglot.utils.JwtUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author ZJ
 */
@Service
public class SitInfoServiceImpl extends ServiceImpl<SitInfoMapper, SitInfo> implements ISitInfoService {

    @Resource
    private SitInfoMapper sitInfoMapper;

    @Resource
    private ISitInfoService sitInfoService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private ParkMapper parkMapper;

    @Resource
    private ChargerMapper chargerMapper;

    @Resource
    private PublicService publicService;

    @Resource
    private UserRecordMapper userRecordMapper;

    @Override
    public CodeMsg<List<SitInfo>> querySitList(Map<String, Object> map) {
        if (map.isEmpty()) {
            return new CodeMsg<List<SitInfo>>().setCode(400).setMsg("参数缺失");
        }
        Page<SitInfo> page = new Page<>((int) map.get("current"), (int) map.get("pageSize"));
        QueryWrapper<SitInfo> SitInfoQueryWrapper = new QueryWrapper<>();
        if (map.get("stationId") != null && !map.get("stationId").equals("")) {
            SitInfoQueryWrapper.eq("station_id", map.get("stationId"));
        }
        if (map.get("station") != null && !map.get("station").equals("")) {
            SitInfoQueryWrapper.like("station", map.get("station"));
        }
        if (map.get("identifier") != null && !map.get("identifier").equals("")) {
            SitInfoQueryWrapper.like("identifier", map.get("identifier"));
        }
        if (map.get("stationType") != null && !map.get("stationType").equals("")) {
            SitInfoQueryWrapper.eq("station_type", map.get("stationType"));
        }
        if (map.get("state") != null && !map.get("state").equals("")) {
            SitInfoQueryWrapper.eq("state", map.get("state"));
        }
        IPage<SitInfo> sitInfoPage = sitInfoMapper.selectPage(page, SitInfoQueryWrapper);
        List<SitInfo> sitInfoList = sitInfoPage.getRecords();
        return new CodeMsg<List<SitInfo>>().setCode(200).setMsg(String.valueOf(sitInfoPage.getTotal())).setData(sitInfoList);
    }

    @Override
    public CodeMsg<String> addSit(SitInfo sitInfo) {
        QueryWrapper<SitInfo> sitInfoQueryWrapper = new QueryWrapper<>();
        sitInfoQueryWrapper.lambda().eq(SitInfo::getStation, sitInfo.getStation())
                .eq(SitInfo::getIdentifier, sitInfo.getIdentifier());
        SitInfo getSitInfo = sitInfoMapper.selectOne(sitInfoQueryWrapper);
        if (getSitInfo != null) {
            return new CodeMsg<String>().setCode(400).setMsg("车位信息已存在，添加失败");
        }
        if (sitInfo.getStationId() != null) {
            sitInfo.setStationId(null);
        }
        int insert = sitInfoMapper.insert(sitInfo);
        if (insert == 1) {
            return new CodeMsg<String>().setCode(200).setMsg("添加成功");
        }
        return new CodeMsg<String>().setCode(401).setMsg("添加失败");
    }

    @Override
    public CodeMsg<String> updateState(int[] stationIds, int state) {
        List<SitInfo> sitInfoList = new ArrayList<>();
        for (int id : stationIds) {
            sitInfoList.add(new SitInfo().setStationId(id).setState(state));
        }
        if (sitInfoService.updateBatchById(sitInfoList)) {
            return new CodeMsg<String>().setCode(200).setMsg("操作成功");
        }
        return new CodeMsg<String>().setCode(400).setMsg("操作失败");
    }

    @Override
    public CodeMsg<String> removeSit(int[] stationIds) {
        List<Integer> sitInfoList = new ArrayList<>();
        for (int id : stationIds) {
            sitInfoList.add(id);
        }
        if (sitInfoService.removeByIds(sitInfoList)) {
            return new CodeMsg<String>().setCode(200).setMsg("删除成功");
        }
        return new CodeMsg<String>().setCode(400).setMsg("删除失败");
    }

    @Override
    public CodeMsg<String> updateSit(SitInfo sitInfo) {
        int update = sitInfoMapper.updateById(sitInfo);
        if (update == 1) {
            return new CodeMsg<String>().setCode(200).setMsg("编辑成功");
        }
        return new CodeMsg<String>().setCode(401).setMsg("编辑失败");
    }

    @Transactional
    @Override
    public CodeMsg<SitInfo> getParkingLot(Map<String, String> map) {
        if (map.isEmpty() || map.get("token") == null) {
            return new CodeMsg<SitInfo>().setCode(400).setMsg("参数缺失");
        }
        User user = userMapper.selectById(JwtUtil.verify(map.get("token")).getClaim("id").asString());
        if (user == null || user.getStationType() == null) {
            return new CodeMsg<SitInfo>().setCode(401).setMsg("用户信息出错");
        }
        if (user.getCarNumber() == null || user.getTel() == null) {
            return new CodeMsg<SitInfo>().setCode(201).setMsg("用户信息不完整");
        }
        if (user.getState() == 2) {
            return new CodeMsg<SitInfo>().setCode(402).setMsg("账号被冻结，有问题请找管理员");
        } else if (user.getState() == 3) {
            return new CodeMsg<SitInfo>().setCode(403).setMsg("账号欠费，请支付以往的停车费后，账号自动激活");
        }
        if (user.getParkingLot() != 0) {
            return new CodeMsg<SitInfo>().setCode(202).setMsg("已停车").setData(sitInfoMapper.selectById(user.getParkingLot()));
        }
        String state = "1";
        if (map.get("state") != null) {
            state = map.get("state");
        }
        QueryWrapper<SitInfo> sitInfoQueryWrapper = new QueryWrapper<>();
        sitInfoQueryWrapper.lambda().eq(SitInfo::getStationType, user.getStationType())
                .eq(SitInfo::getState, state);
        List<SitInfo> sitInfoList = sitInfoMapper.selectList(sitInfoQueryWrapper);
        if (sitInfoList.size() >= 1) {
            SitInfo sitInfo = sitInfoList.get(0);
            user.setParkingLot(sitInfo.getStationId());
            sitInfo.setState(2);
            Park park = new Park().setStartPark(LocalDateTime.now())
                    .setCarId(user.getCarId())
                    .setStationType(user.getStationType())
                    .setCarNumber(user.getCarNumber())
                    .setStationId(sitInfo.getStationId());
            userMapper.updateById(user);
            sitInfoMapper.updateById(sitInfo);
            parkMapper.insert(park);
            return new CodeMsg<SitInfo>().setCode(200).setMsg("获取成功").setData(sitInfo);
        } else {
            return new CodeMsg<SitInfo>().setCode(203).setMsg("车位已满，请等待");
        }
    }

    @Override
    public CodeMsg<SitInfo> isParkingLot(Map<String, String> map) {
        if (map.isEmpty()) {
            return new CodeMsg<SitInfo>().setCode(400).setMsg("参数缺失");
        }
        User user = userMapper.selectById(JwtUtil.verify(map.get("token")).getClaim("id").asString());
        if (user == null) {
            return new CodeMsg<SitInfo>().setCode(401).setMsg("用户信息出错");
        }
        if (user.getParkingLot() != 0) {
            return new CodeMsg<SitInfo>().setCode(200).setMsg("已停车").setData(sitInfoMapper.selectById(user.getParkingLot()));
        } else {
            return new CodeMsg<SitInfo>().setCode(201).setMsg("未停车");
        }
    }

    @Transactional
    @Override
    public CodeMsg<Park> endParkingLot(Map<String, String> map) {
        if (map.isEmpty()) {
            return new CodeMsg<Park>().setCode(400).setMsg("参数缺失");
        }
        String id = publicService.getUserIdByToken(map.get("token"));
        User user = userMapper.selectById(id);
        if (user == null) {
            return new CodeMsg<Park>().setCode(401).setMsg("用户不存在");
        } else if (user.getParkingLot() == null || user.getParkingLot() == 0) {
            return new CodeMsg<Park>().setCode(401).setMsg("用户未停车");
        }
        SitInfo sitInfo = sitInfoMapper.selectById(user.getParkingLot());

        //获取停车时间
        QueryWrapper<Park> parkQueryWrapper = new QueryWrapper<>();
        parkQueryWrapper.lambda().eq(Park::getCarId, user.getCarId())
                .eq(Park::getStationId, sitInfo.getStationId()).isNull(Park::getEndPark);
        Park park = parkMapper.selectOne(parkQueryWrapper);
        LocalDateTime endPark = LocalDateTime.now();
        Duration duration = Duration.between(park.getStartPark(), endPark);
        long hours = duration.toHours() + 1;

        //获取收费信息
        QueryWrapper<Charger> chargerQueryWrapper = new QueryWrapper<>();
        chargerQueryWrapper.lambda().eq(Charger::getCardType, user.getCardType())
                .eq(Charger::getStationType, user.getStationType()).eq(Charger::getState, 1);
        Charger charger = chargerMapper.selectOne(chargerQueryWrapper);
        BigDecimal charge = new BigDecimal(10);
        if (charger != null) {
            charge = charger.getCharge();
        }
        BigDecimal price = charge.multiply(BigDecimal.valueOf(hours));

        // 如果停车记录未支付超过5条，用户记录为欠费状态
        QueryWrapper<Park> getParkCount = new QueryWrapper<>();
        getParkCount.lambda().eq(Park::getCarId, user.getCarId()).eq(Park::getState, 1);
        final Integer integer = Math.toIntExact(parkMapper.selectCount(getParkCount));
        if (integer >= 5){
            user.setState(3);
            userRecordMapper.insert(new UserRecord().setUserId(user.getCarId()).setMsg("用户欠费停用账号").setRecordTime(LocalDateTime.now()));
        }

        //更新信息
        user.setParkingLot(0);
        sitInfo.setState(1);
        park.setCardType(user.getCardType()).setEndPark(endPark).setSumPark((int) hours).setFee(price);
        userMapper.updateById(user);
        sitInfoMapper.updateById(sitInfo);
        parkMapper.updateById(park);
        return new CodeMsg<Park>().setCode(200).setMsg("获取成功").setData(park);
    }
}
